package com.michaelbulava.TFS.vc.tfsitem;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.michaelbulava.TFS.common.item.ServerItemPath;
import com.michaelbulava.TFS.log.FileLogger;
import com.michaelbulava.TFS.tasks.vc.QueryItemsExtendedTask;
import com.microsoft.tfs.core.clients.versioncontrol.GetItemsOptions;
import com.microsoft.tfs.core.clients.versioncontrol.exceptions.PathTooLongException;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.*;
import com.microsoft.tfs.util.CollatorFactory;

import java.text.MessageFormat;
import java.util.*;


/**
 * Created by MichaelA on 7/22/2015.
 */
public class TFSFolder extends TFSItem {
    private Map<String, TFSItem> children;
    private final Logger log = FileLogger.getInstance(TFSFolder.class);

    public TFSFolder(ServerItemPath path, Workspace workspace){//}, Project project) {
        super(path, workspace);//, project);
    }

    public TFSFolder(ExtendedItem extendedItem, Workspace workspace){//, Project project) {
        super(extendedItem, workspace);//, project);
    }

    public Set<TFSItem> getChildren(){
        return getChildren(false);
    }

    public Set<TFSItem> getChildren(boolean showDeletedItems){
        if (children == null)
            computeChildren(showDeletedItems);
        return new HashSet(children.values());
    }

    public void setChildrenEmpty(){
        children = new TreeMap<String, TFSItem>(CollatorFactory.getCaseInsensitiveCollator());
    }

    private void computeChildren(boolean showDeletedItems){
        setChildrenEmpty();

        DeletedState deletedState = showDeletedItems ? DeletedState.ANY : DeletedState.NON_DELETED;
        GetItemsOptions itemsOptions = GetItemsOptions.INCLUDE_BRANCH_INFO;
        if (showDeletedItems)
            itemsOptions = itemsOptions.combine(GetItemsOptions.INCLUDE_SOURCE_RENAMES);

        QueryItemsExtendedTask task = new QueryItemsExtendedTask(null, getWorkspace(), getFullPath(), ItemType.ANY,
                deletedState, RecursionType.ONE_LEVEL, itemsOptions);

        ProgressManager.getInstance().run(task);

        if (!task.isOk()){
            String messageFormat = "Could not query extended items for {0}:{1}";
            String message = MessageFormat.format(messageFormat, new Object[] { getFullPath(), task.getException().getLocalizedMessage()});
            log.error(message, task.getException());
        }

        ExtendedItem[][] childExtendedItems = task.getItems();
        if (childExtendedItems.length != 1)
            return;
        for(int i = 0; i < childExtendedItems[0].length; i++){
            TFSItem childItem = TFSItemFactory.getItem(childExtendedItems[0][i], getWorkspace());//, getProject());
            if (!equals(childItem))
                addChild(childItem);
        }

        TFSItem[] implicitChildren = TFSItemFactory.getImplicitAdds(this);
        for(int i = 0; i < implicitChildren.length; i++)
            addChild(implicitChildren[i]);
    }

    public Set<TFSItem> getFolderChildren(){
        return getFolderChildren(false);
    }

    public Set<TFSItem> getFolderChildren(boolean includeDeletedItems){
        Set<TFSItem> folderChildren = new HashSet<TFSItem>(getChildren(includeDeletedItems));
        for(Iterator<TFSItem> i = folderChildren.iterator(); i.hasNext();){
            if(!(i.next() instanceof TFSFolder))
                i.remove();
        }
        return folderChildren;
    }

    public void clearCachedChildren(){
        children = null;
    }




    public void addChild(TFSItem child){
        if (children == null)
            setChildrenEmpty();
        String childFullPath = child.getFullPath();
        if (child.getDeletionID() != 0) {
            TFSItem existingChild = (TFSItem)children.get(childFullPath);
            if (existingChild != null) {
                if (existingChild.getDeletionID() == 0)
                    return;

                if (existingChild.getDeletionID() > child.getDeletionID())
                    return;
            }
        }
        children.put(childFullPath, child);
    }


    public TFSItem getChildByFullPath(String fullPathToChild) {
        if (children == null)
            computeChildren(false);

        return (TFSItem)children.get(fullPathToChild);
    }

    public TFSItem getDescendantByFullPath(String fullPathToChild) {
        TFSItem returnme = getChildByFullPath(fullPathToChild);
        if (returnme == null) {
            int indexOfChildFinishingSlash = fullPathToChild.indexOf('/', getFullPath().length() + 1);
            if (indexOfChildFinishingSlash == -1)
                return null;

            String nextChildFullPath = fullPathToChild.substring(0, indexOfChildFinishingSlash);
            TFSItem directChild = getChildByFullPath(nextChildFullPath);
            if ((directChild == null) || (!(directChild instanceof TFSFolder)))
                return null;

            return ((TFSFolder)directChild).getDescendantByFullPath(fullPathToChild);
        }
        return returnme;
    }

    public boolean areChildrenCached() {
        return children != null;
    }

    public boolean hasChildren() {
        return getChildren().size() > 0;
    }

    public boolean hasFolderChildren() {
        return getFolderChildren().size() > 0;
    }

    public boolean testAttribute(Object target, String name, String value) {
        if ((target instanceof TFSFolder)) {
            TFSFolder folder = (TFSFolder)target;
            String serverPath = folder.getFullPath();
            WorkingFolder exactFolder;
            boolean isMapped;
            try {
                exactFolder = getWorkspace().getExactMappingForServerPath(serverPath);
                isMapped = getWorkspace().isServerPathMapped(serverPath);
            } catch (PathTooLongException e) {
                exactFolder = null;
                isMapped = false;
            }
            if (name.equals("MappingState")) {
                if (value.equals("Unmapped"))
                    return (!isMapped) && (exactFolder == null);

                if (value.equals("ExactMapping"))
                    return (exactFolder != null) && (!exactFolder.isCloaked());

                if (value.equals("MappedByParent"))
                    return (isMapped == true) && (exactFolder == null);

                if (value.equals("Cloaked"))
                    return (exactFolder != null) && (exactFolder.isCloaked() == true);

            }
        }
        return false;
    }


}
